package com.ecgsystem.panel;

import java.util.concurrent.ConcurrentLinkedQueue;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.ecgsystem.R;
import com.ecgsystem.activity.OfflineECG;
import com.ecgsystem.constants.Commons;
import com.ecgsystem.constants.Constants;
import com.ecgsystem.thread.ThreadGetSignalByFrame;

/**
 * @author anhtuan
 * 
 */
public class Panels extends SurfaceView implements SurfaceHolder.Callback, Constants {
	/*
	 * 1 o nho 1mm voi toc do 25 mm/s 1mm = 0.04s 1mm = 4px 1s = 100 px tan so
	 * lay mau a(s) lenght = 0.04/a * 62.5 = 2.5 /a khoang cach a * 25 *
	 * PixelPerMm
	 */
	private Paint grid;
	private Paint line;
	private Paint text;
	private Paint borderline;
	private Paint linebase;
	private Bitmap _bitmap;
	private float x[][];
	private ConcurrentLinkedQueue<Float> QueueDraw[];

	/**
	 * TODO Put here a description of this field.
	 */
	public static int WIDTH;
	/**
	 * TODO Put here a description of this field.
	 */
	public static int HEIGHT = Commons.HEIGHT;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float baseline[];

	/**
	 * TODO Put here a description of this field.
	 */
	public static float PixelPerMm = (int)(Commons.HEIGHT / 105);

	/**
	 * TODO Put here a description of this field.
	 */
	public static float zoom = 7;
	
	/**
	 * tan so lay mau f
	 */
	public static float fx = 0.002f; // 0.002s 1 mau
	// toc do giay
	/**
	 * TODO Put here a description of this field.
	 */
	public static float v = 25; // 25mm/s
	// so diem ve tren ca ban
	private int ARRAYLENGHT;

	private static float MIN_ZOOM = 1f;
	private static float MAX_ZOOM = 5f;

	private float scaleFactor = 1.f;
	private ScaleGestureDetector detector;
	private PointF mid;

	private SurfaceHolder _holder;

	/**
	 * TODO Put here a description of what this constructor does.
	 *
	 * @param context
	 */
	public Panels(final Context context) {
		super(context);

		this.ARRAYLENGHT = Math.round(60 / (v * fx));// co 12 o lon
		this.x = new float[4][this.ARRAYLENGHT * 4];
		baseline = new float[3];

		// mang toa do x

		this.setVisibility(VISIBLE);
		this.setEnabled(true);
		this.setZOrderOnTop(false);

		this.borderline = new Paint();
		this.borderline.setColor(getResources().getColor(R.color.borderline));
		this.borderline.setStrokeWidth(3);

		this.text = new Paint();
		this.text.setColor(Color.RED);
		this.text.setTextSize(14);
		this.text.setTypeface(Typeface.DEFAULT_BOLD);

		this.grid = new Paint();
		this.grid.setColor(getResources().getColor(R.color.grid));
		this.grid.setStrokeWidth(1);

		this.line = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.line.setStyle(Paint.Style.FILL_AND_STROKE);
		this.line.setColor(getResources().getColor(R.color.line));
		this.line.setAntiAlias(true);
		this.line.setStrokeWidth(2f);

		this.linebase = new Paint();
		this.linebase.setColor(Color.GRAY);
		this.linebase.setAntiAlias(true);
		this.linebase.setStrokeWidth(0.5f);

		this.detector = new ScaleGestureDetector(context, new ScaleListener());
		this.mid = new PointF();

		this.getHolder().addCallback(this);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param QueueDraw
	 */
	public void setQueueDraw(final ConcurrentLinkedQueue<Float> QueueDraw[]) {
		this.QueueDraw = QueueDraw;
		this._holder = getHolder();
		this._holder.addCallback(this);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param progress
	 */
	public void startDraw(){
		
	}
	public void startDrawAt(int progress) {
		Canvas c = null;
		c = this._holder.lockCanvas(null);
		synchronized (this._holder) {
			if (this._bitmap != null && c != null) {
				c.save();
				c.scale(this.scaleFactor, this.scaleFactor, this.mid.x, this.mid.y);

				Draw(c, new Canvas(this._bitmap), progress);
				c.restore();
			}
		}
		if (c != null) {
			this._holder.unlockCanvasAndPost(c);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// Let the ScaleGestureDetector inspect all events.
		if (ev.getAction() == 261) {
			float x = (ev.getX(0) + ev.getX(1)) / 2;
			float y = (ev.getY(0) + ev.getY(1)) / 2;
			this.mid.set(x, y);
		}
		this.detector.onTouchEvent(ev);
		return true;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		WIDTH = width;//(int) (width * this.scaleFactor);
		HEIGHT = Commons.HEIGHT;
		this._bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_4444);
		baseline[0] = (float) (17.5 * PixelPerMm) ;
		baseline[1] = (float) (52.5 * PixelPerMm);
		baseline[2] = (float) (87.5 * PixelPerMm);
		float temp = v * fx * PixelPerMm;
		float width4 = PixelPerMm * 60;
		for (int j = 0; j < this.ARRAYLENGHT; j++) {
			for (int i = 0; i < 4; i++) {
				this.x[i][j] = temp * j + i * width4;
			}
		}

		Canvas c = null;
		try {
			c = holder.lockCanvas(null);
			synchronized (holder) {
				Draw(c, new Canvas(this._bitmap), 0);
				c.restore();
			}
		} finally {
			if (c != null) {
				holder.unlockCanvasAndPost(c);
			}
		}

	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param vCanvas
	 * @param iCanvas
	 * @param progress
	 */
	public void Draw(final Canvas vCanvas, final Canvas iCanvas, final int progress) {
		// TODO Auto-generated method stub
		// V蘯?� l??��盻�?n?�?�?n
		DrawGrid(iCanvas);
		Float drawArray[][] = new Float[12][];
		if (OfflineECG.startDraw) {
			for (int i = 0; i < 12; i++) if(ThreadGetSignalByFrame.hasRecord[i]){
				drawArray[i] = this.QueueDraw[i].toArray(new Float[0]);
				for (int j = 0; j < drawArray[i].length; j++) {
					drawArray[i][j] = this.signalToY(i, drawArray[i][j]);
				}
			}
			int index = 0;
			int startIndex = 0;
			index = 5000 * progress / 100;
			if (index > this.ARRAYLENGHT)
				startIndex = index - this.ARRAYLENGHT;
			else
				startIndex = 0;
			if(index > drawArray[0].length){
				index = drawArray[0].length;
			}

			if (this.QueueDraw != null && OfflineECG.startDraw == true) {
				for (int no = 0; no < 12; no++) if(ThreadGetSignalByFrame.hasRecord[no]){
					for (int i = 0, j = startIndex; j < index - 1; i++, j++) {
						iCanvas.drawLine(this.x[no / 3][i], drawArray[no][j],
								this.x[no / 3][i + 1], drawArray[no][j + 1], this.line);
					}
				}
			}
		}
		if (this._bitmap != null && vCanvas != null)
			vCanvas.drawBitmap(this._bitmap, 0, 0, null);
	}

	private float signalToY(int stt, float signal) {
		float y = 0;
		int i = stt % 3;
		y = baseline[i] - signal * zoom * 10;
		if (y < baseline[i] - HEIGHT / 6) {
			y = baseline[i] - HEIGHT / 6;
		}
		if (y > baseline[i] + HEIGHT / 6) {
			y = baseline[i] + HEIGHT / 6;
		}
		return y;
	}

	private void DrawGrid(Canvas c) {

		this._bitmap.eraseColor(getResources().getColor(R.color.background));
		float t = 0;
		int i = 0;
		Paint draw;
		while (t < WIDTH) {
			if (i % 12 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(t, 0, t, HEIGHT, draw);
			t += 5 * PixelPerMm;
			i++;
		}

		// Draw horizontal line
		t = 0;
		i = 0;
		while (t < HEIGHT) {
			if (i % 7 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(0, t, WIDTH, t, draw);
			t += 5 * PixelPerMm;
			i++;
		}

		// c.drawText(typeECG, 10, 20, text);
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			Panels.this.scaleFactor *= detector.getScaleFactor();
			Panels.this.scaleFactor = Math.max(MIN_ZOOM, Math.min(Panels.this.scaleFactor, MAX_ZOOM));
			invalidate();
			return true;
		}
	}

	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub.
		
	}

	public void surfaceDestroyed(SurfaceHolder arg0) {
		// TODO Auto-generated method stub.
		
	}
}